雖然我們在上一章節中完成的部署已經可以使用了。然而,在現代應用部署中,我們還需要考慮高可用性、自動恢復以及部署更新和回滾等需求。為了實現這些目標,我們需要使用 Deployment
來管理和擴展我們的應用部署。
Deployment
是 Kubernetes 中用來管理 Pod
副本的資源。你可以將 Deployment
視為一組 Pod 的聲明,這些 Pod
具有相同的規格和標籤。Deployment
會自動確保這些 Pod 的數量保持在您指定的副本數,並在 Pod
失敗或節點發生故障時自動替換它們。
Deployment
是 Kubernetes 中用來管理 Pod
副本的資源,它可以自動創建和管理 ReplicaSet
,而 ReplicaSet
則確保有足夠數量的 Pod
在運行,這樣 Deployment
可以輕鬆實現應用程式的滾動更新、擴展以及回滾操作,確保應用始終處於穩定的狀態。
簡單來說:Deployment
-> 管理 ReplicaSet
-> 管理 Pod
。
Pod
是 Kubernetes 中最小的可部署單位,通常包含一個或多個容器。Pod
是應用程式的實際執行單元。ReplicaSet
的作用是確保系統中有一組指定數量的 Pod
副本在運行。如果有 Pod
失效或被刪除,ReplicaSet
會自動創建新的 Pod
來補充。Deployment
主要用於聲明式地管理應用程式的生命週期。它可以用來滾動更新、擴展或回滾應用程式版本,並確保應用程式始終保持在期望的狀態。Deployment
會自動創建並管理一個或多個 ReplicaSet
ReplicaSet
是 Deployment
的底層實現部分。雖然你可以直接使用 ReplicaSet
,但通常更推薦通過 Deployment
來管理,因為 Deployment
提供了更多高級功能,如滾動更新和回滾。
Deployment
來逐步替換現有的 Pod
,確保應用在更新過程中始終可用。Deployment
可以自動回滾到上一個穩定的版本,減少停機時間和風險。Deployment
調整副本數量,自動擴展 Pod
,從而提高應用的處理能力。Deployment
可以用來自動部署新的應用版本,確保快速迭代和部署。Deployment
可以在多個節點上運行多個 Pod
副本,確保應用在單個 Pod
或節點故障時仍然可用。Deployment
在不同的環境(如開發、測試、預發布、正式環境)中部署相同的應用版本,確保一致性和隔離性。以下是等下會使用的 Deployment
組態檔案範例,使用 YAML 格式:
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo-deployment
spec:
replicas: 3
selector:
matchLabels:
app: foo
template:
metadata:
labels:
app: foo
spec:
containers:
- name: foo
image: lofairy/foo
apiVersion: apps/v1
:指定使用的 Kubernetes API 版本,這裡使用的是 apps/v1
,通常用於 Deployment、DaemonSet、StatefulSet 等資源。kind: Deployment
:指定這個資源的類型是 Deployment。metadata
:Deployment 的元數據設定。
name: foo-deployment
:Deployment 的名稱是 foo-deployment
。spec
:Deployment 的規格設定。
replicas: 3
:指定要運行的 Pod 副本數量為 3,這意味著 Kubernetes 會保持有 3 個相同的 Pod 在集群中運行。selector
:定義選擇 Pod 的標準。
matchLabels
:選擇包含標籤 app: foo
的 Pod,來關聯這些 Pod 到這個 Deployment。template
:Pod 模板,Deployment 會根據這個模板來創建 Pod。
metadata
:Pod 的元數據設定。
labels
:定義 Pod 的標籤為 app: foo
。spec
:Pod 的規格設定。
containers
:這個 Pod 包含的容器設定。
name: foo
:容器的名稱是 foo
。image: lofairy/foo
:容器將使用 lofairy/foo
這個 Docker 鏡像來啟動。透過這個組態檔案,Kubernetes 會建立一個名為 foo-deployment
的 Deployment,並確保始終有三個使用指定 lofairy/foo
映像檔的 Pod 在集群中運行。
今天我們的目標是將上一章部署的 Pod 改用 Deployment 部署,並模擬回滾需求。示意圖如下:
kubectl delete -f pod.yaml
組態檔案: deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo-deployment
spec:
replicas: 3
selector:
matchLabels:
app: foo
template:
metadata:
labels:
app: foo
spec:
containers:
- name: foo
image: lofairy/foo
kubectl apply -f deployment.yaml
儘管我們使用 Deployment 重新創建了 Pod 副本,但不需要對已有的 Service 進行任何修改。Service 是通過選擇器來根據標籤篩選 Pod 並進行流量導向的,它會自動尋找並連接到符合條件的 Pod,對所有目標 Pod 進行基本的負載均衡(Load Balancing)。Deployment 組態檔案設定的 Pod 標籤與昨天的 Pod 組態檔案相同。
for i in {1..10}; do curl -s 0.0.0.0:30000/hostname; echo; done
---
{"hostname":"foo-deployment-66587db9f-vjgdn"}
{"hostname":"foo-deployment-66587db9f-qr9qr"}
{"hostname":"foo-deployment-66587db9f-qr9qr"}
{"hostname":"foo-deployment-66587db9f-qr9qr"}
{"hostname":"foo-deployment-66587db9f-xpltq"}
{"hostname":"foo-deployment-66587db9f-xpltq"}
{"hostname":"foo-deployment-66587db9f-qr9qr"}
{"hostname":"foo-deployment-66587db9f-vjgdn"}
{"hostname":"foo-deployment-66587db9f-vjgdn"}
{"hostname":"foo-deployment-66587db9f-vjgdn"}
在 Deployment 中,spec.replicas
欄位用來指定應維持的 Pod 副本數量。透過這個設定,我們可以輕鬆地實現水平擴展,以及在多區域 (節點) 中進行部署。
kubectl get pod -o wide
---
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
foo-deployment-66587db9f-8pjsh 1/1 Running 0 15s 10.244.1.8 wslkind-worker <none> <none>
foo-deployment-66587db9f-p2mfk 1/1 Running 0 5m35s 10.244.2.15 wslkind-worker2 <none> <none>
foo-deployment-66587db9f-z544f 1/1 Running 0 5m35s 10.244.1.7 wslkind-worker <none> <none>
spec.replicas
調整成 5 個kubectl scale deployment foo-deployment --replicas 5
kubectl get pod -o wide
---
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
foo-deployment-66587db9f-4wg7c 1/1 Running 0 5s 10.244.2.18 wslkind-worker2 <none> <none>
foo-deployment-66587db9f-8pjsh 1/1 Running 0 2m25s 10.244.1.8 wslkind-worker <none> <none>
foo-deployment-66587db9f-gptw4 1/1 Running 0 5s 10.244.2.19 wslkind-worker2 <none> <none>
foo-deployment-66587db9f-p2mfk 1/1 Running 0 7m45s 10.244.2.15 wslkind-worker2 <none> <none>
foo-deployment-66587db9f-z544f 1/1 Running 0 7m45s 10.244.1.7 wslkind-worker <none> <none>
Deployment 實現了 Rollout 的特性,無論是初次創建資源,還是更新 Deployment 的 PodTemplateSpec
,都會生成 Rollout 的歷史記錄。
kubectl rollout history deployment foo-deployment
---
REVISION CHANGE-CAUSE
1 <none>
在上面改變副本數量並沒有留下紀錄,因為這個特性是透過 ReplicaSet 實現,而不是 Pod 本身自帶的
接下來我們來更新我們的應用程式,這次我們將 PodTemplateSpec
裡的 image 更新為 lofairy/bar
kubectl set image deployment foo-deployment foo=lofairy/bar
kubectl describe deployment foo-deployment
結果如下
Name: foo-deployment
Namespace: default
[...]
Pod Template:
Labels: app=foo
Containers:
foo:
Image: lofairy/bar
[...]
curl 0.0.0.0:30000
---
bar
可以看到,新版本應用已經更新部署。
kubectl rollout history deployment foo-deployment
---
REVISION CHANGE-CAUSE
1 <none>
2 <none>
你可能注意到,CHANGE-CAUSE
欄位中沒有任何信息,這使得追踪和判別 Deployment 的變更原因變得困難。CHANGE-CAUSE
的內容實際上是從 Deployment 的 kubernetes.io/change-cause
註解中繼承而來。要設定或修改 CHANGE-CAUSE
,可以採取以下兩種方法:
kubectl annotate
命令為 Deployment 添加註解。metadata
部分手動修改,添加或更新 kubernetes.io/change-cause
註解,以記錄變更的原因。kubectl annotate
命令新增註解kubectl annotate deployment foo-deployment kubernetes.io/change-cause="image changed to lofairy/bar"
kubectl rollout history deployment foo-deployment
---
REVISION CHANGE-CAUSE
1 <none>
2 image changed to lofairy/bar
假如我們應用出了問題,需要將應用程式退版,可以使用 kubectl rollout undo
指令。
kubectl rollout undo deployment foo-deployment
curl 0.0.0.0:30000
---
foo
kubectl rollout history deployment foo-deployment
---
REVISION CHANGE-CAUSE
2 image changed to lofairy/bar
3 <none>
在執行回滾操作時,被回滾的版本號會消失,並且回滾的內容會移到最新的版本位置。也就是說,回滾後的版本號將會變成最新的修訂版本。
當你執行 kubectl rollout undo
時,Kubernetes 會執行以下步驟:
這意味著:
記得清理這幾天建立的資源,方便之後的實作練習。
kubectl delete -f pod.yaml -f service.yaml -f deployment.yaml
# 或是一次性的刪除所有對應的組態檔案
kubectl delete -f .
到今天為止,我們已經學會了如何通過程式撰寫、容器編譯和 Kubernetes 部署來實現我們的應用。然而,這只是 Kubernetes 整體中很小的一部分。在接下來的時間裡,我們將按照主題一步步深入了解 Kubernetes 的資源及其設計上的特點。